'''

    Test for desktop ubik app
    
Created on 9 avr. 2011

@author: dee
'''

_icon = [
"16 16 2 1",
#". c None",
". c #EE0000",
"# c #000000",
".##########.....",
"################",
"##........#####.",
"...######.......",
"..#########.....",
".###############",
"###.####..######",
"###..##..###....",
".###....###.....",
"..########......",
"...######.......",
"................",
"................",
"................",
"................",
"................"
]

import sys, time

from PyQt4 import QtGui, QtCore

import SHIK._sysevents

class Pixmap(QtGui.QGraphicsWidget):
    clicked = QtCore.pyqtSignal()
    entered = QtCore.pyqtSignal()
    leaved = QtCore.pyqtSignal()

    def __init__(self, pix, blurFactor=0.0, parent=None):
        super(Pixmap, self).__init__(parent)
        self.setAcceptHoverEvents(True)
        self.blurFactor = blurFactor*1.0
        self.setPix(pix)
    
    def setPix(self, pix):
        if self.blurFactor:
            w = pix.width()
            pix = pix.scaledToWidth(w/self.blurFactor, QtCore.Qt.SmoothTransformation)
            pix = pix.scaledToWidth(w, QtCore.Qt.SmoothTransformation)
        self.orig = QtGui.QPixmap(pix)
        
    def paint(self, painter, option, widget):
        painter.drawPixmap(QtCore.QPointF(), self.orig)

    def mousePressEvent(self, ev):
        self.clicked.emit()

    def hoverEnterEvent(self, ev):
        self.entered.emit()

    def hoverLeaveEvent(self, ev):
        self.leaved.emit()

class AppWin(QtGui.QGraphicsView):
    hidden = QtCore.pyqtSignal()
    
    def __init__(self, *args, **kwargs):
        super(AppWin, self).__init__(*args, **kwargs)
        self.resize( 600, 300 )

        # Background
        screenPixmap = QtGui.QPixmap.grabWindow(QtGui.QApplication.desktop().winId())
        size = screenPixmap.size()
        
        self.scene = QtGui.QGraphicsScene(0, 0, size.width(), size.height())
        self.scene.setBackgroundBrush(QtCore.Qt.white)

        self.pixmap = Pixmap(screenPixmap, 10)
        self.connect(
            self.pixmap, QtCore.SIGNAL( "clicked()" ),
            self.toggleVisible
        )
        self.pixmap.setGeometry(QtCore.QRectF(0.0, 0.0, size.width(), size.height()))
        self.scene.addItem(self.pixmap)

        # Buttons
        button = QtGui.QPushButton("Quit DashTop")
        self.connect(
            button, QtCore.SIGNAL( "clicked()" ),
            self.close
        )
        buttonProxy = QtGui.QGraphicsProxyWidget()
        buttonProxy.setWidget(button)
        buttonProxy.setPos(50, 50)
        ds = QtGui.QGraphicsDropShadowEffect()
        ds.setBlurRadius(15)
        buttonProxy.setGraphicsEffect(ds)
        self.scene.addItem(buttonProxy)

        button1 = QtGui.QPushButton("Change State")
        self.connect(
            button1, QtCore.SIGNAL( "clicked()" ),
            self.do
        )
        buttonProxy = QtGui.QGraphicsProxyWidget()
        buttonProxy.setWidget(button1)
        buttonProxy.setPos(size.width()/2.0, size.height()/2.0)
        ds = QtGui.QGraphicsDropShadowEffect()
        ds.setBlurRadius(15)
        buttonProxy.setGraphicsEffect(ds)
        button1.ds = ds
        self.scene.addItem(buttonProxy)
        
        button2 = QtGui.QPushButton("Close")
        self.connect(
            button1, QtCore.SIGNAL( "clicked()" ),
            self.do
        )
        button2Proxy = QtGui.QGraphicsProxyWidget()
        button2Proxy.setWidget(button2)
        button2Proxy.setPos(size.width()/2.0, (size.height()/2.0)+0)
        button2Proxy.setOpacity(0)
        ds = QtGui.QGraphicsDropShadowEffect()
        ds.setBlurRadius(15)
        button2Proxy.setGraphicsEffect(ds)
        button1.ds = ds
        self.scene.addItem(button2Proxy)

        o = 0
        pixs = list()
        for pictName in ('furnace', 'nuke', 'trapcode'):
            p = QtGui.QPixmap("../resources/"+pictName+".png")
            pixmap = Pixmap(p)
            self.connect(
                pixmap, QtCore.SIGNAL( "clicked()" ),
                self.doPix
            )
            pixmap.setGeometry(QtCore.QRectF(size.width()/2.0, size.height()/2.0+o+p.width(), p.width(), p.height()))
            o += p.width() + 10
            ds = QtGui.QGraphicsDropShadowEffect()
            ds.setBlurRadius(30)
            ds.setOffset(18)
            pixmap.setGraphicsEffect(ds)
            button1.ds = ds
            self.scene.addItem(pixmap)
            pixs.append(pixmap)

        self.setScene(self.scene)
        self.setFrameStyle(0)
        #self.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        #window.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        #window.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        
        # Tray icon
        self._trayIcon = QtGui.QSystemTrayIcon(QtGui.QIcon(QtGui.QPixmap(_icon)), self)
        self.connect(
            self._trayIcon, QtCore.SIGNAL( "activated(QSystemTrayIcon::ActivationReason)" ),
            self.onTrayClick
        )

        menu = QtGui.QMenu(self)
        action = QtGui.QAction("Quit", self)
        self.connect(
            action, QtCore.SIGNAL( "triggered()" ),
            self.close
        )
        menu.addAction(action)
        grpMenu = menu.addMenu( "SubMenu" )
        action = QtGui.QAction("Toggle", self)
        grpMenu.addAction( action )
        self.connect(
            action, QtCore.SIGNAL( "triggered()" ),
            self.toggleVisible
        )

        self._trayIcon.setContextMenu(menu)
        self._trayIcon.show()
        
        # System Hook
        self.lastTime = 0
        self.threshold = 0.5
        self.hit = 0
        SHIK._sysevents.add_key_press(self.press)
        #SHIK._sysevents.add_key_release(self.release)
        SHIK._sysevents.init()
        
        
        # States
        if 1:
            self.machine = QtCore.QStateMachine()
            state1 = QtCore.QState(self.machine)
            state2 = QtCore.QState(self.machine)
            state3 = QtCore.QState(self.machine)
            self.machine.setInitialState(state1)
            
            tf = 2
            
            # State 1.
            state1.assignProperty(button1, 'text', "Open")
            state1.assignProperty(button2Proxy, 'opacity', 0)
            state1.assignProperty(self.pixmap, 'pos', QtCore.QPointF(0, 0))
            state1.assignProperty(button1, 'pos', QtCore.QPointF(size.width()/2.0, size.height()/2.0))
            for pix in pixs:
                state1.assignProperty(pix, 'rotation', 180)
                state1.assignProperty(pix, 'opacity', 0)
                state1.assignProperty(pix, 'pos', QtCore.QPointF(size.width()/2.0, pix.y()))
                
            # State 2.
            state2.assignProperty(button1, 'text', "More...")
            state2.assignProperty(button2Proxy, 'opacity', 1)
#            state2.assignProperty(self.pixmap, 'pos', QtCore.QPointF(-size.width()/(6.0*tf), 0))
            state2.assignProperty(self.pixmap, 'pos', QtCore.QPointF(0, 0))
            state2.assignProperty(button1, 'pos', QtCore.QPointF(size.width()/3.0, size.height()/2.0))
            for pix in pixs:
                state2.assignProperty(pix, 'rotation', 0)
                state2.assignProperty(pix, 'opacity', 1)
                state2.assignProperty(pix, 'pos', QtCore.QPointF(size.width()/2.0-size.width()/(6.0*tf), pix.y()))
    
            # State 3.
            state3.assignProperty(button1, 'text', "Less")
            state3.assignProperty(button2Proxy, 'opacity', 0)
            state3.assignProperty(self.pixmap, 'pos', QtCore.QPointF(-size.width()/2.0, 0))
            state3.assignProperty(button1, 'pos', QtCore.QPointF(size.width()/2.0, size.height()/3.0))
            for pix in pixs:
                state3.assignProperty(pix, 'opacity', 0)

            # Transitions
            lag = 150
            
            t1 = state1.addTransition(button1.clicked, state2)
            p = QtCore.QPropertyAnimation(self.pixmap, 'pos', state1)
            p.setEasingCurve(QtCore.QEasingCurve.OutBack)
            t1.addAnimation(p)
            p = QtCore.QPropertyAnimation(button1, 'text', state1)
            p.setEasingCurve(QtCore.QEasingCurve.OutBack)
            t1.addAnimation(p)
            p = QtCore.QPropertyAnimation(button1, 'pos', state1)
            p.setEasingCurve(QtCore.QEasingCurve.OutBack)
            t1.addAnimation(p)
            t1.addAnimation(QtCore.QPropertyAnimation(button2Proxy, 'opacity', state1))
            for i, pix in enumerate(pixs):
                p = QtCore.QPropertyAnimation(pix, 'rotation', state1)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t1.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'pos', state1)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t1.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'opacity', state1)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                t1.addAnimation(p)
    
            t2 = state2.addTransition(button1.clicked, state3)
            p = QtCore.QPropertyAnimation(self.pixmap, 'pos', state2)
            p.setEasingCurve(QtCore.QEasingCurve.OutBack)
            t2.addAnimation(p)
            t2.addAnimation(QtCore.QPropertyAnimation(button1, 'text', state2))
            p = QtCore.QPropertyAnimation(button1, 'pos', state2)
            p.setEasingCurve(QtCore.QEasingCurve.OutBack)
            t2.addAnimation(p)
            t2.addAnimation(QtCore.QPropertyAnimation(button2Proxy, 'opacity', state2))
            for i, pix in enumerate(pixs):
                p = QtCore.QPropertyAnimation(pix, 'rotation', state2)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t2.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'pos', state2)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t2.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'opacity', state2)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                t2.addAnimation(p)

            t3 = state3.addTransition(button1.clicked, state2)
            t3.addAnimation(QtCore.QPropertyAnimation(self.pixmap, 'pos', state3))
            t3.addAnimation(QtCore.QPropertyAnimation(button1, 'text', state3))
            t3.addAnimation(QtCore.QPropertyAnimation(button1, 'pos', state3))
            t3.addAnimation(QtCore.QPropertyAnimation(button2Proxy, 'opacity', state3))
            for i, pix in enumerate(pixs):
                p = QtCore.QPropertyAnimation(pix, 'rotation', state3)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t3.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'pos', state3)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t3.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'opacity', state3)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                t3.addAnimation(p)

            t4 = state2.addTransition(button2.clicked, state1)
            t4.addAnimation(QtCore.QPropertyAnimation(self.pixmap, 'pos', state2))
            t4.addAnimation(QtCore.QPropertyAnimation(button1, 'text', state2))
            t4.addAnimation(QtCore.QPropertyAnimation(button1, 'pos', state2))
            t4.addAnimation(QtCore.QPropertyAnimation(button2Proxy, 'opacity', state2))
            for i, pix in enumerate(pixs):
                p = QtCore.QPropertyAnimation(pix, 'rotation', state2)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t4.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'pos', state2)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t4.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'opacity', state2)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                t4.addAnimation(p)

            t5 = state3.addTransition(self.hidden, state1)
            t5.addAnimation(QtCore.QPropertyAnimation(self.pixmap, 'pos', state3))
            t5.addAnimation(QtCore.QPropertyAnimation(button1, 'text', state3))
            t5.addAnimation(QtCore.QPropertyAnimation(button1, 'pos', state3))
            t5.addAnimation(QtCore.QPropertyAnimation(button2Proxy, 'opacity', state3))
            for i, pix in enumerate(pixs):
                p = QtCore.QPropertyAnimation(pix, 'rotation', state3)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t5.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'pos', state3)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250+i*lag)
                t5.addAnimation(p)
                p = QtCore.QPropertyAnimation(pix, 'opacity', state3)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                t5.addAnimation(p)

            for pix in pixs:
                pix.machine = QtCore.QStateMachine()
                defaultState = QtCore.QState(pix.machine)
                defaultState.assignProperty(pix, 'scale', 1)
                pix.machine.setInitialState(defaultState)
                
                hiState = QtCore.QState(pix.machine)
                hiState.assignProperty(pix, 'scale', 1.3)
                
                toHi = defaultState.addTransition(pix.entered, hiState)
                p = QtCore.QPropertyAnimation(pix, 'scale', defaultState)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250)
                toHi.addAnimation(p)
                
                toDef = hiState.addTransition(pix.leaved, defaultState)
                p = QtCore.QPropertyAnimation(pix, 'scale', hiState)
                p.setEasingCurve(QtCore.QEasingCurve.OutBack)
                p.setDuration(250)
                toDef.addAnimation(p)
                
                pix.machine.start()
            
            self.machine.start()

    def onTrayClick(self, reason):
        if reason == QtGui.QSystemTrayIcon.Trigger:
            self.toggleVisible()
                
    def toggleVisible(self):
        if self.isVisible():
            self.hidden.emit()
            return self.hide()
        return self.show()

    def toggleFullScreen(self):
        if self.isFullScreen():
            #self.enableMask(True)
            self.showNormal()
        else:
            #self.enableMask(False)
            self.showFullScreen()

    def press(self, k):
        if self.isVisible():
            return
        
        if k == 'Lcontrol':
            curTime = time.time()
            #print 'delay:', curTime - self.lastTime
            if curTime - self.lastTime < self.threshold:
                self.hit += 1
            else:
                self.hit = 1
            if self.hit >= 3:
                self.toggleVisible()
                self.lastTime = 0
                self.hit = 0
            else:
                self.lastTime = curTime
            #print 'press', repr(k)
        else:
            self.lastTime = 0
        
#    def release(self, k):
#        print 'release', k
    
    def show(self):
        self.pixmap.setPix(QtGui.QPixmap.grabWindow(QtGui.QApplication.desktop().winId()))
        super(AppWin, self).show()
    
    def do(self):
        print 'Do it...'
        
    def doPix(self):
        print 'Do Pix'
        
def run():
    app = QtGui.QApplication(sys.argv)

    w = AppWin()
    w.showFullScreen()
    
    ret = app.exec_()
    return ret


if __name__ == '__main__':
    sys.exit(run())
